package mvp.com.bbc.viewpagerlayoutmanager;

import android.os.Build;
import android.view.View;

/**
 * Created by ${cbf} on 2017/11/30.
 * 渐变效果的viewpager
 */

public class GalleryLayoutManager extends ViewPagerLayoutManager {

    private int itemSpace;
    private float moveSpeed;
    private float maxAlpha;
    private float minAlpha;
    private float angle;
    private boolean flipRotate;

    public GalleryLayoutManager(int itemSpace) {
        this(new Builder(itemSpace));
    }

    public GalleryLayoutManager(int itemSpace, int moveSpeed) {
        this(new Builder(itemSpace).setMoveSpeed(moveSpeed));
    }

    public GalleryLayoutManager(int itemSpace, int moveSpeed, boolean reverseLayout) {
        this(new Builder(itemSpace).setMoveSpeed(moveSpeed).setReverseLayout(reverseLayout));
    }

    public GalleryLayoutManager(int itemSpace, int moveSpeed, int maxAlpha, int minAlpha, boolean flipRotate) {
        this(new Builder(itemSpace).setMoveSpeed(moveSpeed).setMaxAlpha(maxAlpha).setMinAlpha(maxAlpha).setFlipRotate(flipRotate));
    }


    public GalleryLayoutManager(int itemSpace, float moveSpeed, int orientation, float angle, float minAlpha,
                                float maxAlpha, boolean flipRotate, boolean reverseLayout) {
        super(orientation, reverseLayout);
        setIntegerDy(true);
        this.itemSpace = itemSpace;
        this.moveSpeed = moveSpeed;
        this.angle = angle;
        this.maxAlpha = maxAlpha;
        this.minAlpha = minAlpha;
        this.flipRotate = flipRotate;
    }

    public GalleryLayoutManager(Builder builder) {
        this(builder.itemSpace, builder.moveSpeed,
                builder.orientation, builder.angle, builder.minAlpha,
                builder.maxAlpha, builder.flipRotate, builder.reverseLayout);
    }

    @Override
    protected float setInterval() {
        return mDecoratedMeasurement + itemSpace;
    }

    @Override
    protected void setItemViewProperty(View itemView, float targetOffset) {
        final float rotation = calRotation(targetOffset);
        if (getOrientation() == HORIZONTAL) {
            if (flipRotate)
                itemView.setRotationX(rotation);
            else
                itemView.setRotationY(rotation);
        } else {
            if (flipRotate)
                itemView.setRotationY(-rotation);
            else
                itemView.setRotationX(-rotation);
        }
        final float alpha = calAlpha(targetOffset);
        itemView.setAlpha(alpha);
        if (getEnableBringCenterToFront() &&
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            itemView.setElevation(alpha * 5);
        }

    }

    @Override
    protected float setViewElevation(View itemView, float targetOffset) {
        return calAlpha(targetOffset) * 5;
    }

    @Override
    protected float getDistanceRatio() {
        if (moveSpeed == 0) return Float.MAX_VALUE;
        return 1 / moveSpeed;
    }

    private float calAlpha(float targetOffset) {
        float alpha = (minAlpha - maxAlpha) / mInterval * Math.abs(targetOffset) + maxAlpha;
        if (alpha < minAlpha) alpha = minAlpha;
        return alpha;
    }

    private float calRotation(float targetOffset) {
        return -angle / mInterval * targetOffset;
    }

    public int getOrientation() {
        return super.getOrientation();
    }

    public int getItemSpace() {
        return itemSpace;
    }

    public float getMoveSpeed() {
        return moveSpeed;
    }

    public float getMaxAlpha() {
        return maxAlpha;
    }

    public float getMinAlpha() {
        return minAlpha;
    }

    public float getAngle() {
        return angle;
    }

    public boolean getFlipRotate() {
        return flipRotate;
    }

    public void setItemSpace(int itemSpace) {
        assertInLayoutOrScroll(null);
        if (this.itemSpace == itemSpace) return;
        this.itemSpace = itemSpace;
        removeAllViews();
    }

    public void setOrientation(int orientation) {
        super.setOrientation(orientation);
    }

    public void setMoveSpeed(float moveSpeed) {
        assertInLayoutOrScroll(null);
        if (this.moveSpeed == moveSpeed) return;
        this.moveSpeed = moveSpeed;
    }

    public void setMaxAlpha(float maxAlpha) {
        assertInLayoutOrScroll(null);
        if (maxAlpha > 1) maxAlpha = 1;
        if (this.maxAlpha == maxAlpha) return;
        this.maxAlpha = maxAlpha;
        requestLayout();
    }

    public void setMinAlpha(float minAlpha) {
        assertInLayoutOrScroll(null);
        if (minAlpha > 0) minAlpha = 0;
        if (this.minAlpha == minAlpha) return;
        this.minAlpha = minAlpha;
        requestLayout();
    }

    public void setAngle(float angle) {
        assertInLayoutOrScroll(null);
        if (this.angle == angle) return;
        this.angle = angle;
        requestLayout();
    }

    public void setFlipRotate(boolean flipRotate) {
        assertInLayoutOrScroll(null);
        if (this.flipRotate == flipRotate) return;
        this.flipRotate = flipRotate;
        requestLayout();
    }

    public static class Builder {
        private static float INTERVAL_ANGLE = 30f;
        private static final float DEFAULT_SPEED = 1f;
        private static float MIN_ALPHA = 0.5f;
        private static float MAX_ALPHA = 1f;
        private int itemSpace;
        private float moveSpeed;
        private int orientation;
        private float maxAlpha;
        private float minAlpha;
        private float angle;
        private boolean flipRotate;
        private boolean reverseLayout;

        public Builder(int itemSpace) {
            this.itemSpace = itemSpace;
            this.angle = INTERVAL_ANGLE;
            this.moveSpeed = DEFAULT_SPEED;
            this.minAlpha = MIN_ALPHA;
            this.maxAlpha = MAX_ALPHA;
            flipRotate = false;
            reverseLayout = false;
        }

        public Builder setItemSpace(int itemSpace) {
            this.itemSpace = itemSpace;
            return this;
        }

        public Builder setMoveSpeed(float moveSpeed) {
            this.moveSpeed = moveSpeed;
            return this;
        }

        public Builder setOrientation(int orientation) {
            this.orientation = orientation;
            return this;
        }

        public Builder setMaxAlpha(float maxAlpha) {
            this.maxAlpha = maxAlpha;
            return this;
        }

        public Builder setMinAlpha(float minAlpha) {
            this.minAlpha = minAlpha;
            return this;
        }

        public void setAngle(float angle) {
            this.angle = angle;
        }

        public Builder setFlipRotate(boolean flipRotate) {
            this.flipRotate = flipRotate;
            return this;
        }

        public Builder setReverseLayout(boolean reverseLayout) {
            this.reverseLayout = reverseLayout;
            return this;
        }

        public GalleryLayoutManager build() {
            return new GalleryLayoutManager(this);
        }
    }
}
